home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 2006-2009 Pearl Crescent, LLC. All Rights Reserved. */
- /* vim: set sw=2 sts=2 ts=8 et syntax=javascript: */
-
- /*
- * This file is part of the Pearl Crescent Utility Functions Library.
- */
-
- if (!com) var com = {};
- if (!com.aviary) com.aviary = {};
- if (!com.aviary.talon) com.aviary.talon = {};
- if (!com.aviary.talon.grab) com.aviary.talon.grab =
- {
- kSelectionPopupElemID: "AviarySelectionPopup",
- kPortionCanvasID: "AviaryPortionCanvas", // Gray w/crosshairs.
- kPortionWinCanvasID: "AviaryWindowCanvas", // Window image.
- kPortionBoxID: "AviaryPortionBox",
- kPortionInfoID: "AviaryPortionInfoBox",
- kPortionDimensionBoxID: "AviaryPortionDimensionBox", // in info box
- kPortionBtnBoxID: "AviaryPortionBtnBox", // in info box
- kDefaultSelectionFillStyle: "rgba(128,128,128,0.5)",
- kMinWidth: 6, // When adjusting, box will be 6x6 or larger.
- kLeftAlignInfoBox: true, // Change as desired.
-
- mUtilObj: null,
- mWindow: null,
- mCanvasRect: {},
- mSelectionFillStyle: null,
- mMaxCanvasDimension: 0,
- mAllowAdjustment: false,
- mCaptureFunc: null,
- mCaptureArg: null,
-
- mBrowserElem: null,
- mIsDrawing: false,
- mIsAdjusting: false, // Initial rect has been drawn and may be adjusted.
- mIsMovingBox: false,
- mIsResizingBox: false,
- mDidCapture: false,
- mPopupScreenX: 0, // mPopupScreenX, mPopupScreenY are popup's top, left.
- mPopupScreenY: 0,
- mStartX: 0,
- mStartY: 0,
- mSelectionWidth: 0, // Only valid when mIsAdjusting is true.
- mSelectionHeight: 0, // Only valid when mIsAdjusting is true.
- mAdjustOffsetX: 0, // Offset within the box where mousedown occurred.
- mAdjustOffsetY: 0,
- mAdjustHorz: 0,
- mAdjustVert: 0,
- mPopupElem: null, // Popup (the container for everything).
- mCanvasElem: null, // Gray w/crosshairs.
- mWinCanvasElem: null, // Image of window contents.
- mPortionBoxElem: null, // Surrounded by dashed lines; shown during adjustment.
- mInfoBoxElem: null, // Container for dimension labels and buttons.
- mButtonBoxElem: null, // Container for buttons (within info box).
- mDimensionBoxLabelElem1: null, // label element with pearl-template="PROP"
- mDimensionBoxLabelElem2: null, // label element with pearl-template="PROP"
- mDimensionBoxLabelTemplate1: null, // e.g., "%S w" or "%1$S x %2$S pixels"
- mDimensionBoxLabelTemplate2: null, // e.g., "%S h" or null
- mFFZoomLevel: 1,
-
- // aCaptureFunc is called like:
- // aCaptureFunc(browserWin, portionRect, captureArg);
- // where portionRect includes: startX, startY, pageW, pageH properties.
- // If the user cancelled the grab, aCaptureFunc() will be called with a
- // null portionRect.
- init: function(aBrowserWin, aBrowserWinVisRect, aSelectionFillStyle,
- aMaxCanvasDimension, aAllowAdjustment, aCaptureFunc,
- aCaptureArg)
- {
- this.mUtilObj = com.aviary.talon.pearlutil;
-
- this.mWindow = aBrowserWin;
- this.mCanvasRect = aBrowserWinVisRect;
- this.mSelectionFillStyle = (aSelectionFillStyle)
- ? aSelectionFillStyle
- : this.kDefaultSelectionFillStyle;
-
- if (aMaxCanvasDimension && aMaxCanvasDimension > 0)
- this.mMaxCanvasDimension = aMaxCanvasDimension;
- else
- {
- var ua = navigator.userAgent;
- var isWinOrMac = (ua.indexOf("Macintosh") >= 0
- || ua.indexOf("Windows") >= 0);
- this.mMaxCanvasDimension = isWinOrMac ? 32767 : 32766;
- }
-
- this.mAllowAdjustment = aAllowAdjustment;
- this.mCaptureFunc = aCaptureFunc;
- this.mCaptureArg = aCaptureArg;
-
- this.mBrowserElem = top.getBrowser().selectedBrowser;
- this.mIsDrawing = false;
- this.mIsAdjusting = false;
- this.mIsMovingBox = false;
- this.mIsResizingBox = false;
- this.mDidCapture = false;
- this.mPopupScreenX = 0;
- this.mPopupScreenY = 0;
- this.mStartX = 0;
- this.mStartY = 0;
- this.mSelectionWidth = 0;
- this.mSelectionHeight = 0;
- this.mAdjustOffsetX = 0;
- this.mAdjustOffsetY = 0;
- this.mAdjustHorz = 0;
- this.mAdjustVert = 0;
- this.mPortionBoxElem = null;
- this.mInfoBoxElem = null;
- this.mButtonBoxElem = null;
- this.mDimensionBoxLabelElem1 = null;
- this.mDimensionBoxLabelElem2 = null;
- this.mDimensionBoxLabelTemplate1 = null;
- this.mDimensionBoxLabelTemplate2 = null;
- this.mFFZoomLevel = 1;
- this.mWinCanvasElem = document.getElementById(this.kPortionWinCanvasID);
- this.mPopupElem = document.getElementById(this.kSelectionPopupElemID);
- if (this.mPopupElem)
- {
- document.popupNode = this.mBrowserElem;
-
- this.mPortionBoxElem = document.getElementById(this.kPortionBoxID);
- if (this.mPortionBoxElem)
- this.mPortionBoxElem.setAttribute("hidden", "true");
- var dimBoxElem = document.getElementById(this.kPortionDimensionBoxID);
- if (dimBoxElem && this.mUtilObj)
- {
- var dimElems = this.mUtilObj.GetElementsByAttr(dimBoxElem,
- "pearl-template", null);
- if (dimElems)
- {
- this.mDimensionBoxLabelElem1 = dimElems[0];
- this.mDimensionBoxLabelTemplate1 =
- dimElems[0].getAttribute("pearl-template");
- if (dimElems.length > 1)
- {
- this.mDimensionBoxLabelElem2 = dimElems[1];
- this.mDimensionBoxLabelTemplate2 =
- dimElems[1].getAttribute("pearl-template");
- }
- }
- }
- this.mButtonBoxElem = document.getElementById(this.kPortionBtnBoxID);
- this.mInfoBoxElem = document.getElementById(this.kPortionInfoID);
- if (this.mInfoBoxElem)
- {
- // Set top and left so size is available, and hide info box for now.
- this.mInfoBoxElem.style.top = "0px";
- this.mInfoBoxElem.style.left = "0px";
- }
- this.showElement(this.mInfoBoxElem, false);
- this.showElement(this.mButtonBoxElem, false);
-
- this.mFFZoomLevel = (this.mBrowserElem.boxObject.width
- / this.mBrowserElem.contentWindow.innerWidth);
-
- var r = { startX: 0, startY: 0, pageW: 0, pageH: 0 };
- this.getContentWindowSize(r);
- this.capPortionRect(r);
- this.mCanvasElem = document.getElementById(this.kPortionCanvasID);
- this.setCanvasSize(this.mCanvasElem, r.pageW, r.pageH);
- var self = this;
- window.setTimeout(function() { self.delayedInit(); }, 0);
- }
- },
-
- // delayedInit() is needed so popups such as menus have a chance to close.
- delayedInit: function()
- {
- if (this.mPopupElem)
- {
- // Remove old max width and height so as not to interfere with natural
- // width and height (which are used in initCanvasInPopup() to set
- // max width and max height).
- this.mPopupElem.style.removeProperty("max-width");
- this.mPopupElem.style.removeProperty("max-height");
-
- this.mPopupElem.showPopup(this.mBrowserElem, -1, -1, "popup", "topleft",
- "overlap");
- this.mPopupElem.addEventListener("mousedown", this, true);
- this.mPopupElem.addEventListener("mousemove", this, true);
- }
- },
-
- // Called via "onpopupshown"
- initCanvasInPopup: function()
- {
- this.mDidCapture = false;
-
- if (this.mPopupElem)
- {
- this.mPopupScreenX = this.mPopupElem.boxObject.screenX;
- this.mPopupScreenY = this.mPopupElem.boxObject.screenY;
- }
-
- try
- {
- // Convert from zoomed units to XUL pixel units.
- this.mCanvasRect.pageW =
- Math.round(this.mCanvasRect.pageW * this.mFFZoomLevel);
- this.mCanvasRect.pageH =
- Math.round(this.mCanvasRect.pageH * this.mFFZoomLevel);
- this.capPortionRect(this.mCanvasRect);
- var canvascontext = this.mCanvasElem.getContext("2d");
- canvascontext.fillStyle = this.mSelectionFillStyle;
- canvascontext.fillRect(0, 0,
- this.mCanvasRect.pageW, this.mCanvasRect.pageH);
-
- this.drawWindowInCanvas();
- }
- catch (e) {}
-
- if (this.mPopupElem)
- {
- // Ensure that popup will not grow larger than window content size.
- this.mPopupElem.style.maxWidth = this.mPopupElem.boxObject.width + "px";
- this.mPopupElem.style.maxHeight = this.mPopupElem.boxObject.height + "px";
- }
- },
-
- capPortionRect: function(aRect)
- {
- if (aRect)
- {
- if (aRect.pageW > this.mMaxCanvasDimension)
- aRect.pageW = this.mMaxCanvasDimension;
- if (aRect.pageH > this.mMaxCanvasDimension)
- aRect.pageH = this.mMaxCanvasDimension;
- }
- },
-
- // Sets pageW and pageH properties inside aSizeObj (units are XUL pixels).
- getContentWindowSize: function(aSizeObj)
- {
- aSizeObj.pageW = 0;
- aSizeObj.pageH = 0;
-
- if (this.mBrowserElem)
- {
- var theWin = this.mBrowserElem.contentWindow;
- aSizeObj.pageW = this.mBrowserElem.boxObject.width;
- aSizeObj.pageH = this.mBrowserElem.boxObject.height;
- var hasHorzSB = (theWin.scrollMaxX > 0);
- var hasVertSB = (theWin.scrollMaxY > 0);
- if (!hasHorzSB && !hasVertSB)
- return; // No scrollbars so no further adjustments needed.
-
- try
- {
- // Add hidden element with height=100% and use to account for SB height.
- var tmpElem = theWin.document.createElement("div");
- tmpElem.setAttribute("style", "visibility: hidden; z-index: -1;"
- + " position: fixed; top: 0px; left: 0px;"
- + " margin: 0px; padding: 0px; border: none;"
- + " width: 100%; height: 100%");
- theWin.document.body.appendChild(tmpElem);
- if (hasVertSB)
- aSizeObj.pageW = Math.round(tmpElem.offsetWidth * this.mFFZoomLevel);
- if (hasHorzSB)
- aSizeObj.pageH = Math.round(tmpElem.offsetHeight * this.mFFZoomLevel);
- theWin.document.body.removeChild(tmpElem);
- } catch (e) {}
- }
- },
-
- drawWindowInCanvas: function()
- {
- if (!this.mWinCanvasElem)
- return;
-
- var bgColor = "rgb(255,255,255)";
- if (this.mUtilObj)
- {
- if (!this.mUtilObj.GetBoolPref("browser.display.use_system_colors",
- false))
- {
- bgColor = this.mUtilObj.GetLocalizedStrPref(
- "browser.display.background_color", bgColor);
- }
- }
- // else get system background color... but there is no JS API.
-
- this.setCanvasSize(this.mWinCanvasElem,
- this.mCanvasRect.pageW, this.mCanvasRect.pageH);
-
- var context = this.mWinCanvasElem.getContext("2d");
-
- // Draw the page image.
- context.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
- context.save();
- context.scale(this.mFFZoomLevel, this.mFFZoomLevel);
-
- var right = Math.round(this.mCanvasRect.pageW / this.mFFZoomLevel);
- var bottom = Math.round(this.mCanvasRect.pageH / this.mFFZoomLevel);
- context.drawWindow(this.mWindow, this.mCanvasRect.startX,
- this.mCanvasRect.startY, right, bottom, bgColor);
-
- context.restore();
- },
-
- setCanvasSize: function(aCanvas, aWidth, aHeight)
- {
- aCanvas.style.width = aWidth + "px";
- aCanvas.style.height = aHeight + "px";
- aCanvas.style.maxWidth = aWidth + "px";
- aCanvas.style.maxHeight = aHeight + "px";
- aCanvas.width = aWidth;
- aCanvas.height = aHeight;
- },
-
- handleEvent: function(aEvent)
- {
- if (aEvent.type == "keypress")
- {
- aEvent.preventDefault();
- aEvent.stopPropagation();
- this.cleanUp(); // Cancelled.
- return true;
- }
-
- // The remaining events are mouse events.
- var clientX = aEvent.screenX - this.mPopupScreenX;
- var clientY = aEvent.screenY - this.mPopupScreenY;
-
- if (aEvent.type == "mousemove")
- {
- var canvascontext = this.mCanvasElem.getContext("2d");
- if (!canvascontext) return false;
-
- if (!this.mIsDrawing)
- return this.drawCrossHairs(canvascontext, clientX, clientY);
-
- if (aEvent.ctrlKey || aEvent.shiftKey || aEvent.altKey || aEvent.metaKey)
- return false;
-
- var doUpdateCaptureRegion = false;
- var captureRect = null; // Only used in !this.mIsAdjusting case.
- var right = 0;
- var bottom = 0;
- if (!this.mIsAdjusting)
- {
- right = clientX;
- bottom = clientY;
- captureRect = this.getCaptureRect(clientX, clientY);
- doUpdateCaptureRegion = true;
- }
- else if (this.mIsMovingBox)
- {
- // Move the box, ensuring all sides stay within the canvas.
- this.mStartX = (clientX - this.mAdjustOffsetX);
- if (this.mStartX < 0)
- this.mStartX = 0;
- else if (this.mStartX + this.mSelectionWidth > this.mCanvasRect.pageW)
- this.mStartX = (this.mCanvasRect.pageW - this.mSelectionWidth);
-
- this.mStartY = (clientY - this.mAdjustOffsetY);
- if (this.mStartY < 0)
- this.mStartY = 0;
- else if (this.mStartY + this.mSelectionHeight > this.mCanvasRect.pageH)
- this.mStartY = (this.mCanvasRect.pageH - this.mSelectionHeight);
-
- this.positionBox(this.mStartX, this.mStartY, null, null);
- right = this.mStartX + this.mSelectionWidth;
- bottom = this.mStartY + this.mSelectionHeight;
- doUpdateCaptureRegion = true;
- }
- else if (this.mIsResizingBox)
- {
- // Adjust mouse coords to account for orig. click position in grabber.
- clientX += this.mAdjustOffsetX;
- clientY += this.mAdjustOffsetY;
-
- right = this.mStartX + this.mSelectionWidth;
- bottom = this.mStartY + this.mSelectionHeight;
-
- if (1 == this.mAdjustHorz)
- {
- this.mStartX = clientX;
- if (this.mStartX < 0)
- this.mStartX = 0;
- if (this.mStartX > (right - this.kMinWidth))
- this.mStartX = right - this.kMinWidth;
- }
- else if (-1 == this.mAdjustHorz)
- {
- right = clientX;
- if (right < (this.mStartX + this.kMinWidth))
- right = this.mStartX + this.kMinWidth;
- else if (right > this.mCanvasRect.pageW)
- right = this.mCanvasRect.pageW;
- }
-
- if (1 == this.mAdjustVert)
- {
- this.mStartY = clientY;
- if (this.mStartY < 0)
- this.mStartY = 0;
- if (this.mStartY > (bottom - this.kMinWidth))
- this.mStartY = bottom - this.kMinWidth;
- }
- else if (-1 == this.mAdjustVert)
- {
- bottom = clientY;
- if (bottom < (this.mStartY + this.kMinWidth))
- bottom = this.mStartY + this.kMinWidth;
- else if (bottom > this.mCanvasRect.pageH)
- bottom = this.mCanvasRect.pageH;
- }
- this.mSelectionWidth = right - this.mStartX;
- this.mSelectionHeight = bottom - this.mStartY;
- this.positionBox(this.mStartX, this.mStartY,
- this.mSelectionWidth, this.mSelectionHeight);
- doUpdateCaptureRegion = true;
- }
-
- if (doUpdateCaptureRegion)
- {
- this.drawGrayRects(canvascontext, captureRect, right, bottom);
- this.updateInfoBox(captureRect); // Also shows box if hidden.
- }
-
- aEvent.preventDefault();
- aEvent.stopPropagation();
- return true;
- }
- else if (aEvent.type == "mousedown")
- {
- if (aEvent.ctrlKey || aEvent.shiftKey || aEvent.altKey || aEvent.metaKey)
- return false;
- if (aEvent.button != 0)
- return false;
-
- if (this.mIsAdjusting)
- {
- if (aEvent.target.id == this.kPortionBoxID) // In the box?
- {
- this.mAdjustOffsetX = clientX - this.mStartX;
- this.mAdjustOffsetY = clientY - this.mStartY;
- this.mIsMovingBox = true;
- this.showElement(this.mButtonBoxElem, false);
- this.updateInfoBox(null);
- }
- else // In a grabber.
- {
- var e = aEvent.target;
- this.mAdjustHorz = this.getIntAttribute(e, "adjustHorz");
- this.mAdjustVert = this.getIntAttribute(e, "adjustVert");
-
- if (1 == this.mAdjustHorz)
- this.mAdjustOffsetX = (this.mStartX - clientX);
- else
- {
- var right = this.mStartX + this.mSelectionWidth;
- this.mAdjustOffsetX = this.mAdjustHorz * (clientX - right);
- }
-
- if (1 == this.mAdjustVert)
- this.mAdjustOffsetY = (this.mStartY - clientY);
- else
- {
- var bottom = this.mStartY + this.mSelectionHeight;
- this.mAdjustOffsetY = this.mAdjustVert * (clientY - bottom);
- }
-
- // To avoid mouse cursor "blink", temporarily set the cursor on
- // the box and canvas background to match this grabber's cursor.
- var cursor = e.style.cursor;
- this.setElementCursor(this.mPopupElem, cursor);
- this.setElementCursor(this.mPortionBoxElem, cursor);
-
- this.mIsResizingBox = true;
- this.showElement(this.mButtonBoxElem, false);
- this.updateInfoBox(null);
- }
-
- return true;
- }
- else if (this.mIsDrawing) // workaround for lost mouseup event
- return true;
-
- // First mousedown.
- this.mIsDrawing = true;
- this.mStartX = clientX;
- this.mStartY = clientY;
-
- if (this.mPopupElem)
- {
- this.mPopupElem.addEventListener("mouseup", this, true);
- this.mPopupElem.addEventListener("keypress", this, true);
- }
-
- aEvent.preventDefault();
- aEvent.stopPropagation();
- return true;
- }
- else if (aEvent.type == "mouseup")
- {
- aEvent.preventDefault();
- aEvent.stopPropagation();
-
- if (this.mIsAdjusting)
- {
- if (this.mIsMovingBox)
- {
- this.mIsMovingBox = false;
- this.showElement(this.mButtonBoxElem, true);
- }
- else if (this.mIsResizingBox)
- {
- this.setElementCursor(this.mPopupElem, "default");
- this.setElementCursor(this.mPortionBoxElem, "move");
- this.mIsResizingBox = false;
- this.showElement(this.mButtonBoxElem, true);
- }
- this.updateInfoBox(null);
- }
- else if (this.mIsDrawing)
- {
- var isValidRect = (this.mStartX != clientX && this.mStartY != clientY);
- if (isValidRect)
- {
- var r = this.getCaptureRect(clientX, clientY);
-
- // Ensure that rect coords are in top-bottom and left-right order.
- this.mStartX = r.startX;
- this.mStartY = r.startY;
- this.mSelectionWidth = r.pageW;
- this.mSelectionHeight = r.pageH;
-
- if (!this.mAllowAdjustment)
- this.completeGrab(); // Do not use aEvent after this point.
- else
- this.enterAdjustmentPhase();
- }
- }
-
- return true;
- }
- else if (aEvent.type == "click")
- {
- if (this.mIsAdjusting && 2 == aEvent.detail)
- this.completeGrab(); // Do not use aEvent after this point.
-
- return true;
- }
- },
-
- // Returns true if crosshairs are drawn.
- drawCrossHairs: function(aCanvasCtxt, aClientX, aClientY)
- {
- // Provide initial crosshairs feedback before mouse is pressed.
- aCanvasCtxt.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
- aCanvasCtxt.fillStyle = this.mSelectionFillStyle;
- aCanvasCtxt.fillRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
-
- if (aClientX < 0 || aClientX > this.mCanvasRect.pageW ||
- aClientY < 0 || aClientY > this.mCanvasRect.pageH)
- {
- return false;
- }
-
- aCanvasCtxt.fillStyle = "rgba(255,255,255,0.5)";
- aCanvasCtxt.fillRect(aClientX, 0, 1, this.mCanvasRect.pageH);
- aCanvasCtxt.fillRect(0, aClientY, this.mCanvasRect.pageW, 1);
- return true;
- },
-
- // One corner of the area that is not drawn gray is (aClientX, aClientY).
- // The diagonally opposite corner is (this.mStartX, this.mStartY).
- // It is OK to pass null for aCaptureRect.
- drawGrayRects: function(aCanvasCtxt, aCaptureRect, aClientX, aClientY)
- {
- // Highlight current selection rectangle by clearing entire layer and
- // then redrawing 4 gray rects on sides.
- aCanvasCtxt.clearRect(0, 0, this.mCanvasRect.pageW, this.mCanvasRect.pageH);
- aCanvasCtxt.fillStyle = this.mSelectionFillStyle;
-
- var r = aCaptureRect ? aCaptureRect
- : this.getCaptureRect(aClientX, aClientY);
- if (0 != r.startX)
- aCanvasCtxt.fillRect(0, 0, r.startX, this.mCanvasRect.pageH);
- var w = this.mCanvasRect.pageW - r.startX;
- if (0 != r.startY && 0 != w)
- aCanvasCtxt.fillRect(r.startX, 0, w, r.startY);
- w -= r.pageW;
- var h = this.mCanvasRect.pageH - r.startY;
- if (0 != w && 0 != h)
- aCanvasCtxt.fillRect(r.startX + r.pageW, r.startY, w, h);
- h -= r.pageH;
- if (0 != r.pageW && 0 != h)
- aCanvasCtxt.fillRect(r.startX, r.startY + r.pageH, r.pageW, h);
- },
-
- enterAdjustmentPhase: function()
- {
- // Put up grab handles and "save" button (and dbl-click handler).
- this.mIsAdjusting = true;
- if (this.mPortionBoxElem)
- {
- var box = this.mPortionBoxElem;
- box.style.position = "absolute";
- box.style.overflow = "hidden";
- this.positionBox(this.mStartX, this.mStartY,
- this.mSelectionWidth, this.mSelectionHeight);
- box.style.MozOutlineWidth = "1px";
- box.style.MozOutlineStyle = "dashed";
- box.style.MozOutlineColor = "black";
- this.setElementCursor(box, "move");
- if (this.mUtilObj)
- {
- const kStrName = "REGION_CAPTURE_TOOLTIP";
- var tt = this.mUtilObj.GetLocalizedString(kStrName);
- if (tt && tt != kStrName)
- box.setAttribute("tooltiptext", tt);
- }
- box.addEventListener("click", this, true);
- box.addEventListener("mousedown", this, true);
- box.removeAttribute("hidden");
- this.showElement(this.mButtonBoxElem, true);
- this.updateInfoBox(null);
- }
-
- if (this.mPopupElem)
- {
- // Remove mousedown handler and crosshairs cursor from background.
- this.mPopupElem.removeEventListener("mousedown", this, true);
- this.setElementCursor(this.mPopupElem, "default");
- }
- },
-
- getIntAttribute: function(aElem, aAttr)
- {
- if (!aElem || !aAttr)
- return 0;
-
- return parseInt(aElem.getAttribute(aAttr), 10);
- },
-
- setElementCursor: function(aElem, aCursorName)
- {
- if (aElem && aCursorName)
- aElem.style.setProperty("cursor", aCursorName, "important");
- },
-
- positionBox: function(aLeft, aTop, aWidth, aHeight)
- {
- if (this.mPortionBoxElem)
- {
- const kBorderSize = 1; // Must match box.style.MozOutlineWidth set above.
- aLeft += kBorderSize;
- aTop += kBorderSize;
- this.mPortionBoxElem.style.left = "" + aLeft + "px";
- this.mPortionBoxElem.style.top = "" + aTop + "px";
- if (aWidth)
- {
- var innerW = aWidth - (3 * kBorderSize); // Why 3 * and not 2 *???
- this.mPortionBoxElem.style.width = "" + innerW + "px";
- }
- if (aHeight)
- {
- var innerH = aHeight - (2 * kBorderSize);
- this.mPortionBoxElem.style.height = "" + innerH + "px";
- }
- }
- },
-
- // Reposition, update width and height labels, and show info box.
- // If aCaptureRect is null, coordinates are taken from member variables.
- updateInfoBox: function(aCaptureRect)
- {
- if (!this.mInfoBoxElem)
- return;
-
- var left;
- var top;
- var width;
- var height;
-
- if (aCaptureRect)
- {
- left = aCaptureRect.startX;
- top = aCaptureRect.startY;
- width = aCaptureRect.pageW;
- height = aCaptureRect.pageH;
- }
- else
- {
- left = this.mStartX;
- top = this.mStartY;
- width = this.mSelectionWidth;
- height = this.mSelectionHeight;
- }
-
- // Update dimensions text (one or two labels).
- if (this.mDimensionBoxLabelElem1 && this.mUtilObj)
- {
- if (this.mDimensionBoxLabelElem2)
- {
- this.mDimensionBoxLabelElem1.value = this.mUtilObj
- .GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate1,
- [width], 1);
- this.mDimensionBoxLabelElem2.value = this.mUtilObj
- .GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate2,
- [height], 1);
- }
- else
- {
- this.mDimensionBoxLabelElem1.value = this.mUtilObj
- .GetFormattedLocalizedString(this.mDimensionBoxLabelTemplate1,
- [width, height], 2);
- }
- }
-
- // Set width of info box to match width of region. The box may become
- // wider (as needed to accommodate its contents).
- this.mInfoBoxElem.style.width = "" + width + "px";
- if (0 == this.mInfoBoxElem.boxObject.width)
- {
- // Need to show it to obtain valid width.
- this.showElement(this.mInfoBoxElem, true);
- }
- var infoWidth = this.mInfoBoxElem.boxObject.width;
- var infoHeight = this.mInfoBoxElem.boxObject.height;
-
- // To avoid jumpiness, hide info box while we adjust it.
- this.showElement(this.mInfoBoxElem, false);
- var keepHidden = false;
-
- // Keep the info elements on the popup (don't let popup stretch).
- // Place info below the box, aligned on the right edge if it will fit.
- // If not, try above or inside box (moving it to the right if necessary).
- var newTop = top + height;
- if (infoHeight + newTop >= this.mCanvasRect.pageH)
- {
- // Not enough space below the box.
- if (top > infoHeight) // Place it above the box.
- newTop = top - infoHeight;
- else if (infoHeight < height) // Place it inside.
- newTop = top + height - infoHeight - 10;
- else
- keepHidden = true; // No room for info box.
- }
-
- var newLeft;
- if (this.kLeftAlignInfoBox)
- {
- newLeft = left;
- if (newLeft + infoWidth > this.mCanvasRect.pageW)
- newLeft = this.mCanvasRect.pageW - infoWidth;
- }
- else
- newLeft = left + width - infoWidth;
-
- if (newLeft < 0)
- newLeft = 0;
- if (infoWidth > this.mCanvasRect.pageW)
- keepHidden = true; // No room for info box.
-
- this.mInfoBoxElem.style.top = "" + newTop + "px";
- this.mInfoBoxElem.style.left = "" + newLeft + "px";
-
- if (!keepHidden)
- keepHidden = (0 == width || 0 == height); // Hide if nothing to capture.
- if (!keepHidden)
- this.showElement(this.mInfoBoxElem, true);
- },
-
- showElement: function(aElem, aDoShow)
- {
- if (aElem)
- {
- if (aDoShow)
- aElem.removeAttribute("hidden");
- else
- aElem.setAttribute("hidden", "true");
- }
- },
-
- getCaptureRect: function(aEventClientX, aEventClientY)
- {
- var l, t, r, b;
- if (this.mStartX < aEventClientX)
- {
- l = this.mStartX;
- r = aEventClientX;
- }
- else
- {
- l = aEventClientX;
- r = this.mStartX;
- }
- if (l < 0) l = 0;
- if (r > this.mCanvasRect.pageW) r = this.mCanvasRect.pageW;
-
- if (this.mStartY < aEventClientY)
- {
- t = this.mStartY;
- b = aEventClientY;
- }
- else
- {
- t = aEventClientY;
- b = this.mStartY;
- }
- if (t < 0) t = 0;
- if (b > this.mCanvasRect.pageH) b = this.mCanvasRect.pageH;
-
- return { startX: l, startY: t, pageW: r - l, pageH: b - t };
- },
-
- completeGrab: function(aGrabParam)
- {
- this.mDidCapture = true;
- this.cleanUp();
-
- if (this.mCaptureFunc)
- {
- // TODO: sometimes the captured image has a horizontal or vertical
- // black line in it.
- var r = { startX: this.mStartX, startY: this.mStartY,
- pageW: this.mSelectionWidth, pageH: this.mSelectionHeight };
- r.startX = Math.round(r.startX / this.mFFZoomLevel)
- + this.mWindow.pageXOffset;
- r.startY = Math.round(r.startY / this.mFFZoomLevel)
- + this.mWindow.pageYOffset;
- r.pageW = Math.round(r.pageW / this.mFFZoomLevel);
- r.pageH = Math.round(r.pageH / this.mFFZoomLevel);
-
- this.mCaptureFunc(this.mWindow, r, this.mCaptureArg, aGrabParam);
- }
- },
-
- deinitCanvasInPopup: function()
- {
- if (this.mPopupElem)
- {
- this.mPopupElem.removeEventListener("mousedown", this, true);
- this.mPopupElem.removeEventListener("mousemove", this, true);
- this.mPopupElem.removeEventListener("mouseup", this, true);
- this.mPopupElem.removeEventListener("keypress", this, true);
- }
-
- if (this.mPortionBoxElem)
- {
- this.mPortionBoxElem.removeEventListener("click", this, true);
- this.mPortionBoxElem.removeEventListener("mousedown", this, true);
- }
-
- if (this.mCanvasElem)
- {
- var canvascontext = this.mCanvasElem.getContext("2d");
- if (canvascontext)
- {
- canvascontext.clearRect(0, 0,
- this.mCanvasRect.pageW, this.mCanvasRect.pageH);
- }
- }
- if (this.mWinCanvasElem)
- {
- var canvascontext = this.mWinCanvasElem.getContext("2d");
- if (canvascontext)
- {
- canvascontext.clearRect(0, 0,
- this.mCanvasRect.pageW, this.mCanvasRect.pageH);
- }
- }
-
- // If no capture was done, notify caller after canvas popup is done.
- if (!this.mDidCapture && this.mCaptureFunc)
- {
- var self = this;
- setTimeout(function() { self.mCaptureFunc(self.mWindow, null,
- self.mCaptureArg) }, 0);
-
- }
- },
-
- cleanUp: function()
- {
- if (this.mPopupElem)
- this.mPopupElem.hidePopup();
-
- this.mIsDrawing = false;
- this.mDidCapture = false;
- },
-
- /*
- pearlDumpObj: function(aLabel, aObj)
- {
- if (aObj)
- {
- if (aLabel)
- dump(aLabel + ":\n");
- for (var p in aObj)
- dump(" " + p + ": " + aObj[p] + "\n");
- }
- },
- */
-
- /*
- dumpBoxes: function(aElem, aIndent)
- {
- if (!aIndent)
- aIndent = "";
-
- if (aElem) try
- {
- var node = aElem.QueryInterface(Components.interfaces.nsIDOMNode);
- var w;
- var h;
- var b = "unknown";
- if (node.boxObject)
- {
- w = node.boxObject.width;
- h = node.boxObject.height;
- b = h + (node.boxObject.y - node.parentNode.boxObject.y);
- }
- else
- {
- w = aElem.clientWidth;
- h = aElem.clientHeight;
- }
- var name = node.nodeName;
- var id = node.id ? node.id : "-none-";
- var childCount = node.childNodes.length;
- dump(aIndent + name + " (" + id + ") - w: " + w + ", h: " + h
- + ", b: " + b + " (" + childCount + " children)\n");
- for (var child = node.firstChild; child != null; child = child.nextSibling)
- this.dumpBoxes(child, " " + aIndent);
- } catch (e) { dump(e + "\n"); }
- },
- */
-
- endOfObject: true
- }
-
-